* Reset settings and initialize log file
launch, path("build/turning_points")

*-------------------------------------------------------------------------------
* Price and Wasserman (2024), "The Summer Drop in Female Employment"
*
* Description: Adapt an algorithm from Dupraz, Nakamura, and Steinsson to locate
*              turning points in cyclical time series.
*-------------------------------------------------------------------------------


* Implement the Dupraz et al. algorithm
*-------------------------------------------------------------------------------

capture program drop find_turning_points
program define find_turning_points, rclass
	syntax varname [if], threshold(real) [maxfirst keeplast verbose]
	marksample touse

	* Restrict to specified date range
	preserve
	quietly keep if `touse'

	* Verify that dates are contiguous
	capture assert tm == tm[_n - 1] + 1 if _n > 1
	if _rc != 0 {
		display as error "invalid set of time periods"
		exit = 9
	}

	* Decide how to handle ties: keep either earliest (default) or latest date
	if "`keeplast'" == "" {
		local eq
	}
	else {
		local eq "="
	}

	* Initialize (empty) lists of series minima and maxima
	local minima
	local maxima

	* Initialize time period
	local T = _N
	local t = 1

	* Search for a minimum first unless user requested otherwise
	if "`maxfirst'" != "" {
		local stage "find_max"
	}
	else {
		local stage = "find_min"
	}

	* Specify candidate time period
	local candidate = `t'

	* Loop over time periods
	while (`t' < `T') {
		* Increment time counter
		local t = `t' + 1

		* Test current value against candidate value
		if "`stage'" == "find_min" {
			* Found a local improvement
			if `varlist'[`t'] <`eq' `varlist'[`candidate'] {
				local candidate = `t'
			}
			* Confirmed a local extremum
			else if `varlist'[`t'] > `varlist'[`candidate'] + `threshold' {
				local minima `minima' `=tm[`candidate']'
				local stage "find_max"
			}
		}
		else if "`stage'" == "find_max" {
			if `varlist'[`t'] >`eq' `varlist'[`candidate'] {
				local candidate = `t'
			}
			else if `varlist'[`t'] < `varlist'[`candidate'] - `threshold' {
				local maxima `maxima' `=tm[`candidate']'
				local stage "find_min"
			}
		}
	}

	* Construct a sorted list of turning points
	numlist "`minima' `maxima'", sort
	local extrema = r(numlist)

	* If requested: report the list of turning points
	if "`verbose'" != "" {
		foreach y in "minima" "maxima" "extrema" {
			if "`y'" == "minima" local ylbl "Minimum"
			if "`y'" == "maxima" local ylbl "Maximum"
			if "`y'" == "extrema" local ylbl "Turning point"

			display
			foreach t of local `y' {
				display "`ylbl': " %tmnn/CCYY `t'
			}
		}
	}

	* Return lists of local minima and maxima
	return local minima `minima'
	return local maxima `maxima'
	return local extrema `extrema'
end


* Prepare data
*-------------------------------------------------------------------------------

* Load U-3 unemployment rate and prime-age (25-54) u-rate, LFPR, and EPOP
freduse UNRATE LNU04000060 LNS11300060 LNS12300060, clear

* Clean up the data
assert date(date, "YMD") == daten
gen int tm = ym(year(date(date, "YMD")), month(date(date, "YMD")))
format %tm tm
rename UNRATE urate
rename LNU04000060 prime_urate
rename LNS11300060 prime_lfpr
rename LNS12300060 prime_epop
keep tm urate prime*
order tm urate prime*
gen dates = string(tm, "%tm")

* Focus on 1948-2020
keep if inrange(tm, tm(1948m1), tm(2020m12))
tsset tm


* Estimate turning points
*-------------------------------------------------------------------------------

* Replicate turning points from Dupraz et al.
find_turning_points urate, threshold(1.0) verbose

gen byte knots_dns = 0
foreach t in `=r(extrema)' {
	replace knots_dns = 1 if tm == `t'
}

* Find turning points in prime-age EPOP
find_turning_points prime_epop if inrange(tm, tm(1985m1), tm(2020m12)), threshold(1.0) verbose
find_turning_points prime_epop if inrange(tm, tm(1985m1), tm(2020m12)), threshold(1.0) keeplast verbose

* Find turning points in prime-age LFPR
find_turning_points prime_lfpr if inrange(tm, tm(1985m1), tm(2020m12)), threshold(1.0) verbose
find_turning_points prime_lfpr if inrange(tm, tm(1985m1), tm(2020m12)), threshold(1.0) keeplast verbose

* Specify Price and Wasserman knots
gen knots_pw = inlist(tm, tm(1993m2), tm(2000m4), tm(2003m10), tm(2007m1), tm(2010m6), tm(2014m10))

* Close the log file
unlaunch
